package sketch.util;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import org.eclipse.jdt.core.dom.AST;

import sketch.BatchExecution;
import sketch.ExecutableSequenceContent;
import sketch.subject.TreeMap;

public class SketchUtil {
	public static <T> T[] createArray(T... items) {
	  return items;
	}
	
	public static char intToChar(int i) {
		return (char)i;
	}
	
	public static boolean isPrimitiveOrBoxingType(Class<?> clazz) {
		Checker.checkNull(clazz, "The clazz input could not be null!");
		if (clazz.isPrimitive()) {
			return true;
		}
		if (clazz.equals(Integer.class) || clazz.equals(Float.class) || clazz.equals(Double.class) || clazz.equals(Short.class)
				|| clazz.equals(Byte.class) || clazz.equals(Long.class) || clazz.equals(Boolean.class) || clazz.equals(Character.class)) {
			return true;
		}
		return false;
			
	}
	
	public static boolean print_out = true;
	
	public static void std(String msg) {
		if(print_out)
		  System.out.print(msg);
	}
	
	public static void stdln() {
		if(print_out)
			System.out.println();
	}
	
	public static void stdln(String msg) {
		if(print_out)
		  System.out.println(msg);
	}
	
	public static void std(Object msg) {
		if(print_out)
		  System.out.print(msg);
	}
	
	public static void stdln(Object msg) {
		if(print_out)
		  System.out.println(msg);
	}
	
	public static void flushToStd(String[] msgs) {
		for(String msg : msgs) {
			System.out.println(msg);
		}
	}
	
	public static String arrayToString(Object[] obj) {
		String a  = "";
		for(int i = 0; i < obj.length; i++) {
			if(i > 0) {
				a = a + ", ";
			}
			if(obj[i] == null) {
				a = a + "null";
			} else {
				a =  a+ obj[i].toString();
			}
		}
		return a;
	}
	
	public static BatchExecution batchExecution(ExecutableSequenceContent[] contents) {
		Checker.checkNull(contents, "The executable sequence contents should not be null.");
		ReflectionExecutionOutcome[] results = new ReflectionExecutionOutcome[contents.length];
		
		
		StringBuilder sb = new StringBuilder();
		sb.append(Globals.lineSep);
		for(int index = 0; index < contents.length; index++) {
			ReflectionExecutionOutcome executionOutcome = contents[index].excute();
			results[index] = executionOutcome;
			if(executionOutcome.hasAnyException()) {
				//do not execute any more
				break;
			}
//			sb.append("in batch executing: " + contents[index].toString() + ", result: " + results[index]);
//			sb.append(Globals.lineSep);
		}
//		sb.append(Globals.lineSep);		
//		System.out.println(sb.toString());		
		BatchExecution batchExecution = new BatchExecution(contents, results);		
		return batchExecution;
	}
	
	public static String createVarName(Class<?> clazz) {
		Checker.checkNull(clazz, "The clazz input should not be null.");
		String className = clazz.getName();
		int index = className.lastIndexOf(".");
		if(index != -1) {
		    className = className.substring(index + 1);
		}
		return className.toLowerCase();
	}
	
	public static String removeMethodParam(String methodParam) {
		int index = methodParam.lastIndexOf("(");
		if(index == -1) {
			return methodParam;
		}
		return methodParam.substring(0, methodParam.lastIndexOf("("));
	}
	
	public static String getConstructorNameForSketch(Constructor<?> constructor) {
        StringBuilder sb = new StringBuilder();
		sb.append("<init>");
		sb.append("(");
		Class<?>[] params = constructor.getParameterTypes();
		for(int i = 0; i < params.length; i++) {
			if(i != 0) {
				sb.append(",");
			}
			sb.append(params[i].getName());
		}
		
		sb.append(")");
		
		return sb.toString();
	}
	
	public static String getMethodNameForSketch(Method method) {
		//here we use a simplified signature to identify each method
		//methodname(type1,type2,type3)
		StringBuilder sb = new StringBuilder();
		
		sb.append(method.getName());
		sb.append("(");
		Class<?>[] params = method.getParameterTypes();
		for(int i = 0; i < params.length; i++) {
			if(i != 0) {
				sb.append(",");
			}
			sb.append(params[i].getName());
		}
		
		sb.append(")");
		
		return sb.toString();
	}
	
	public static boolean isNumber(String str) {
		try {
			AST ast = AST.newAST(AST.JLS3);
			ast.newNumberLiteral(str);
		} catch(IllegalArgumentException e) {
			return false;
		}
		return true;
	}
	
	/**
	 * Creates a dir
	 * */
	public static boolean createDir(String dir) {
		return new File(dir).mkdirs();
	}

	/**
	 * Replaces the dot in the name to a slash
	 * */
	public static String transClassNameDotToSlash(String name) {
		return name.replace('.', '/');
	}

	/**
	 * Replaces the slash in the name to a dot
	 * */
	public static String transClassNameSlashToDot(String name) {
		return name.replace('/', '.');
	}
	
	public static String transJavaPathToFileName(File f) {
		Checker.checkTrue(f.getName().endsWith(".java"), "The f : " + f.getAbsolutePath() + " is not a Java file.");
		String name = f.getName();
		return name.substring(0, name.length() - ".java".length());
	}
	
	public static String transJavaFileNameToClassName(String fileName, String packageName) {
		fileName = transClassNameSlashToDot(fileName);
		String removeJava = fileName.substring(0, fileName.indexOf(".java"));
		int lastDot = removeJava.lastIndexOf(".");
		String className = removeJava.substring(lastDot + 1);
		if(packageName != null && !packageName.trim().equals("")) {
			className = packageName + "." + className;
		}
		return className;
	}

	public static void mkdirs(String dir) {
		File f = new File(dir);
		f.mkdirs();
	}
	
	public static boolean isDirInClasspath(String dir) {
		File f = new File(dir);
		if(!f.isDirectory()) {
			return false;
		}
		System.out.println(f.getAbsolutePath());
		String classpath = Globals.getClasspath();
		String[] paths = classpath.split(Globals.pathSep);
		for(String path : paths) {
			File f1 = new File(path);
			if(!f1.isDirectory()) {
				continue;
			}
			try {
				if(f.getCanonicalPath().equals(f1.getCanonicalPath())) {
					return true;
				}
			} catch (IOException e) {
				continue;
			}
			//System.out.println(path + ", is: " + f1.compareTo(f));
		}
		return false;
	}
	
	public static boolean delete_file(String filePath) {
		File f = new File(filePath);
		if(!f.exists() || f.isDirectory()) {
			return false;
		}
		//delete it
		return f.delete();
	}
	
	public static String[] getClassPathEntries() {
		return Globals.getClasspath().split(Globals.pathSep);
	}
	
	public static void main(String[] args) {
		System.out.println("char: " + intToChar(98));
		System.out.println(SketchUtil.createVarName(String.class));
		System.out.println(SketchUtil.createVarName(TreeMap.class));
		System.out.println();
		for(Method m : TreeMap.class.getMethods()) {
			System.out.println(SketchUtil.getMethodNameForSketch(m));
		}
		System.out.println("Show classpath: ");
		boolean r = SketchUtil.isDirInClasspath("./output");
		System.out.println("In? : " + r);
		//test to delete some files
//		boolean r = SketchUtil.delete_file("/homes/gws/szhang/Desktop/sketchtest-release/output/OnlySimpleTransformationExample_instrumented.java");
//		System.out.println("Delete succ? " + r);
	}
}
